#!/usr/bin/perl
#my $Beg=Read('',0x4B); # probably read bytes of file + get size
use strict;
my $cacheDir='cache';
mkdir $cacheDir unless -d $cacheDir;
our $ua;
our $readed=0;
our $dat=shift;
unless ($dat)
{
	{open IN,'DAT/version.txt';undef local $/;$_=<IN>;close IN;}
	die "wrong version format: ".$_ unless /AVDatVersion\s+REG_DWORD\s+0x(\w+)/;
	$dat=hex $1;
}
$dat=~ s/\D//g;
#our $url="avvdat-$dat.zip";
our $url="http://update.nai.com/products/commonupdater/Current/VSCANDAT1000/DAT/0000/avvdat-$dat.zip";
#our $url="http://192.168.16.16/down/upd/avvdat-5244.zip";
our $Size=0;
my $HdrSz=22;
my $HdrApprox=263; # approximate read 

open STDOUT,">>$cacheDir/avvdat-$dat.zip.fetch.log";
open STDERR,'>&STDOUT;';

if ($url=~ /^http:/)
{
use LWP::UserAgent;
use LWP::ConnCache;
#use HTTP::Request;
$ua= LWP::UserAgent->new();
$ua->conn_cache(LWP::ConnCache->new());
#$ua->proxy('http','http://gimly:none@cdit:3128');
$ua->agent("Zip Fetcher by Gimly/1.0");
}

my $OutFile=$url;

$OutFile=$1 if $url=~/\/([^\/]*)$/;
my $UsingCache=0;

my $HdrFile="$cacheDir/$OutFile.hdr";

unlink $HdrFile
if -f $HdrFile && ((stat _)[9] < (stat$0)[9]);

my ($HdrBeg,$Hdr,$Dir,$Sig,@t,$DirBeg,$Mod,$CRC,$PS,$US,$ns,$ts,$At,%need,@At,$name);

if (open IN,$HdrFile)
{	binmode IN;
	seek IN,-$HdrSz,2;
	read IN,$Hdr,$HdrSz;
	($Sig,@t[0..4],$DirBeg,$t[5])=unpack "SSISSIIS",$Hdr;

	$ns=tell IN; # sizeof(HdrFile)
	$Size=$DirBeg+$ns;
	$HdrBeg=$Size-$HdrSz;
	seek IN,0,0;
	read IN,$Dir,$ns-$HdrSz;
	close IN;
print "Using Cache!\n";
$UsingCache=1;
} else {

$Dir=Read(-$HdrSz-$HdrApprox);#Read(-$HdrSz);# read last 22 bytes
$HdrBeg=$Size-$HdrSz;
$Hdr=substr($Dir,-$HdrSz);
($Sig,@t[0..4],$DirBeg,$t[5])=unpack "SSISSIIS",$Hdr;
my $DirSz=$Size-$DirBeg;
my $ToDir=$DirSz-length($Dir);

warn("Need re-read $ToDir/$DirSz more bytes"),
$Dir=Read($DirBeg,$DirBeg+$ToDir-1).$Dir # Read($DirBeg,$HdrBeg) # read Directory
	if $ToDir>0;
$ToDir=length($Dir)-$DirSz;
warn "Loosing $ToDir bytes readed" if $ToDir>0;

#Cache Dir+Header
open OUT,">".$HdrFile;binmode OUT;syswrite OUT,substr($Dir,-$DirSz);close OUT;# $Dir.$Hdr

$Dir=substr($Dir,-$DirSz,-$HdrSz)
}

printf "%08X+%03X Dir\n",$DirBeg, $HdrBeg-$DirBeg;
printf "%08X+%03X Hdr %04X %04X %X %X %X %X %X\n", $HdrBeg, $Size-$HdrBeg, $Sig, @t;
printf "%08X Size\n\n",$Size;

print "Position+Siz  CRC32   PackedSz  UnpSize  Pointer File_Name\n";
for (my ($ptr,$hs)=(0); $ptr<length($Dir);$ptr+=$hs)
{
@t=();
$hs=46;
($Sig,@t[0..4],$Mod,$CRC,$PS,$US,$ns,$ts,@t[5..7],$At)=
	unpack "S6I4SSISII",substr($Dir,$ptr,$hs);

$name=substr($Dir,$ptr+$hs,$ns);
$hs+=$ns+$ts;
printf "%08X+%03X %08X %8X %8X %8X %s\n", $DirBeg+$ptr, $hs, $CRC, $PS, $US,$At, $name;
$need{$At}=[$name,$PS];
push @At,$At;
}

push @At,$DirBeg;
$need{$DirBeg}=['HEADER'];

@At=sort {$a <=> $b} @At;
my (@hdr,@files)=();

my $total=0;
my %cname=();
for (my $i=0;$i<scalar(@At)-1;$i++)
{
	$At=$At[$i];
	my $Nxt=$At[$i+1];
	($name,$PS)=@{$need{$At}};
	$ts=$Nxt-$At-$PS;
	my $hdr=$At.'-'.($At+$ts-1);
	die "Something wrong: Negative header: ts=$ts" if $ts<0;
	$total+=$ts;

	push @hdr,$hdr;
	my $cname="$cacheDir/$OutFile.$name.hdr";
	$cname{$At}=$cname;
	my $wname=$name eq 'legal.txt'?"$cacheDir/$name":"DAT/$name";
	push @files,$cname,$wname;
	printf "At:%08X File:%08X Hdr:%03X %s %s\n", $At, $PS, $ts,$hdr, $name;
}


unless ($UsingCache)
{

die "Too many to download. need $total bytes" if $total>10240;

my @ranges=Read(join',',@hdr);
#print join("\n+++\n",@ranges)."\n<<<<\n";
foreach (@ranges)
{
	
	warn("Bad response: $_"),next
		unless s{Content-[rR]ange: bytes (\d+)-\d+/\d+\r?\n\r?\n}{};
	$At=$1;

	warn("Unknown range: $At"),next
		unless exists $need{$At};

	($name,$PS)=@{$need{$At}};
	my $cname=$cname{$At};
	open BIN,'>'.$cname or warn "$cname: $!";
	binmode BIN;
	syswrite BIN,$_;
	close BIN;
}
print "Readed $readed bytes\n";
}
push @files,$HdrFile;
my $Result='inc/'.$OutFile;

print join(' ','cat',@files,'>',$Result)."\n";
open OUT,'>'.$Result or die "$Result: $!";
binmode OUT;undef $\;
foreach my $file (@files)
{
    open IN,$file or warn "$file: $!";
    binmode IN;
    print OUT while read IN,$_,1024*1024;
    close IN;
}
close OUT;

system("unzip","-t",$Result);
system("sha1sum",$Result);
print "Size: ".(-s $Result)."\n";

sub Read($$)
{
	my ($from,$to)=@_;
	my $rd;
	if (!$to) {$to=$Size}

	if ($ua)
	{
		$from.=-$to if $from>=0 && $from !~ /[,\-]/;
#		my $r=HTTP::Request->new("GET",$url);
		$ua->default_header("Range" => "bytes=".$from);
		print "Reading bytes: ($from)\n";
#		$r=$ua->request($r);
		my $r=$ua->get($url);
		$readed+=length($r->as_string);
		print $r->request->as_string."\n\n".$r->as_string;

		$rd=$r->content();
		$Size=$1 if !$Size && $r->header("Content-Range") =~ m{/(\d+)$};
		if ($r->header("Content-Type")=~ m{ boundary=(\S+)})
		{
			my $bound=$1;
			$rd=~ s/Content-[Tt]ype: .*\r?\n//g;
			$rd =~ s/^.*?\r\n--\Q$bound\E\r\n(.*)\r\n--\Q$bound\E--\r\n.*$/$1/s;
			my @rd=split /\r\n--\Q$bound\E\r\n/,$rd;
#			shift @rd;
#			pop @rd;
			return @rd;
#			$rd=~s{\r\n--\Q$bound\E(--|)\r\n}{\r\n--$MyBound$1\r\n}g;
		}
	}
	else {

    open IN,$url;binmode IN;
	if ($from) {seek IN,$from,$from>0?0:2;$to-=$from}
	read IN,$rd,$to;
	$Size=tell IN unless $Size;
	close IN;
	}

	return $rd;
}

__END__
00000 (hdr 4B) 0004B (file 0000D52) 0000D9C
00D9D (hdr 4E) 00DEB (file 0049CFD) 004AAE7 
4AAE8 (hdr  ) 4AB36 (file 003893D) 0083473
83474 (hdr) 834C0 (file 1116B4D) 119A00C
119A00d (hdr 11d) 119A129

22147a15
16b34c12
45add8df
4388213e

HEADER           |VERSI|GPF  |CompM|Time |Date |CRC32      |Packed Size|Unpacked Sz|NmeSz|EFLen|Name
50 4B 03 04       14 00 02 00 08 00 80 2A 64 38|15 7A 14 22|PP PP PP PP|UU UU UU UU|NN NN|24 00|legal.txt    BLOCK FILE
50 4B 03 04       0A 00 02 00 00 00 80 2A 64 38|12 4C B3 16|FD 9C 04 00|FD 9C 04 00|0C 00|24 00|avvclean.dat BLOCK FILE
50 4B 03 04       0A 00 02 00 00 00 80 2A 64 38|DF D8 AD 45|3D 89 03 00|3D 89 03 00|0C 00|24 00|avvnames.dat BLOCK FILE
50 4B 03 04       0A 00 02 00 00 00 80 2A 64 38|3E 21 88 43|4D 6B 11 01|4D 6B 11 01|0B 00|24 00|avvscan.dat  BLOCK FILE
PK                
GPF: 0-encrypted(0=no,1=yes), 1-dic size (0=4K,1=8K), 2-comp6, 3-comp8
Time: 0-4 Sec/2, 5-10 Min, 11-15 Hour (101 010100 00000 = 5:20:00)
Date: 0-4 Day, 5-9 Mon, 10-15 Year-1980, (1110 00011 00100 = 1994.03.04)



directory: |      M?          ??   |DosTimeDoss|CRC32      |Packed Size|Unpacked Sz|NmeSz|TailSz                    |FF FF FF|Pointer    |
50 4B 01 02 19 00 14 00 02 00 08 00 80 2A 64 38|15 7A 14 22|52 0D 00 00|F1 21 00 00|09 00|23 00|00 00 00 00 04 00 20 50 D6 C4|00 00 00 00|legal.txt    BLOCK
50 4B 01 02 19 00 0A 00 02 00 00 00 80 2A 64 38|12 4C B3 16|FD 9C 04 00|FD 9C 04 00|0C 00|00 00|00 00 00 00 04 00 20 36 50 76|9D 0D 00 00|avvclean.dat
50 4B 01 02 19 00 0A 00 02 00 00 00 80 2A 64 38|DF D8 AD 45|3D 89 03 00|3D 89 03 00|0C 00|00 00|00 00 00 00 04 00 20 34 A4 DE|E8 AA 04 00|avvnames.dat
50 4B 01 02 19 00 0A 00 02 00 00 00 80 2A 64 38|3E 21 88 43|4D 6B 11 01|4D 6B 11 01|0B 00|00 00|00 00 00 00 04 00 20 52 49 1E|73 34 08 00|avvscan.dat


Tail:                                          |PointrToHdr|
50 4B 05 06|00 00 00 00|04 00|04 00|07 01 00 00|0D A0 19 01|00 00

                                    TIMETIMETIMETIMETIMETIM DDDDDDDDDDD M?          DDDDDDDDDDD M?
0A 00 20 00 00 00 00 00 01 00 18 00 00 80 94 64 B7 7D C8 01 00 80 94 64 B7 7D C8 01 60 A4 C3 35 F6 7D C8 01 BLOCK_legal
0A 00 20 00 00 00 00 00 01 00 18 00 00 80 94 64 B7 7D C8 01 56 68 C0 4F F3 7D C8 01 B6 DA 10 46 F3 7D C8 01 BLOCK_avvclean
0A 00 20 00 00 00 00 00 01 00 18 00 00 80 94 64 B7 7D C8 01 78 2E A6 4F F3 7D C8 01 E8 FE 55 46 F3 7D C8 01 BLOCK_avvnames
0A 00 20 00 00 00 00 00 01 00 18 00 00 80 94 64 B7 7D C8 01 8E D7 AB 4E F3 7D C8 01 3E 99 45 43 F3 7D C8 01 BLOCK_avvscan

07 00 1F 00 79 2C 05 A8 8E 2A 07 F1 E3 7B 14 D9 71 4B D6 29 0A E4 FE 81 09 D2 45 9B 8F 4B 0A A0 37 B9 C2    BLOCK_HDR_legal

GET /down/upd/avvdat-5244.zip  HTTP/1.0
Host: update.nai.com
Range: bytes=-22,0-22
